/******************************************************************************
//             INTEL CORPORATION PROPRIETARY INFORMATION
//  This software is supplied under the terms of a license agreement or
//  nondisclosure agreement with Intel Corporation and may not be copied
//  or disclosed except in accordance with the terms of that agreement.
//        Copyright (c) 2000-2001 Intel Corporation. All Rights Reserved.
//
//  Description:
//      Intel(R) JPEG library for X platform 
//
********************************************************************************/
#include "_ijx.h"

#define MAX_COMPONETS 3
#define MAKE_INT16(ptr)	((Ipp16u)(ptr)[1]|((Ipp16u)(ptr)[0]<<8))
#define MAKE_INT32(ptr)	( (((Ipp32u)(ptr)[3])&0xff)|((((Ipp32u)(ptr)[2])<<8)&0xff00)|    \
                          ((((Ipp32u)(ptr)[1])<<16)&0xff0000)|((((Ipp32u)(ptr)[0])<<24)&0xff000000) )
#define ISSTREAMBUFENOUGH(len, usedlen, maxlen) ((BOOL)((maxlen)>=((len)+(usedlen))))


/******************************************************************************
// Name:            _ReadMarkerLength
// Description:     Skip current marker;
// Input Arguments:
//         pStream: Identifies IJBITTREAMSTATE data structure.
// Output Arguments:
//            NONE.
//                          
// Returns:          
//        [Success] marker length
//        [Failure] IJX_RTCODE_F_INSUFFICIENTBUF
//                  IJX_RTCODE_E_ERRPARAM.
//
******************************************************************************/
static IJXRESULT _ReadMarkerLength(IJBITTREAMSTATE *pStream)
{
    int nLen;
    const int nMaxBufBytes=pStream->nMaxBufLen;
    int nUsedBytes=((pStream->nUsedBufBitsLen+7)>>3);
    Ipp8u *ptr;

    if (!ISSTREAMBUFENOUGH(2, nUsedBytes, nMaxBufBytes)) {
        return IJX_RTCODE_W_INSUFFICIENTBUF;
    }
    ptr=&(pStream->pBitStream)[nUsedBytes];
    nLen=MAKE_INT16(ptr);
    if (2>=nLen) {
        return IJX_RTCODE_E_ERRPARAM;
    }

    nLen-=2;

    if (!ISSTREAMBUFENOUGH(nLen, nUsedBytes, nMaxBufBytes)) {
        return IJX_RTCODE_W_INSUFFICIENTBUF;
    }

    pStream->nUsedBufBitsLen=((nUsedBytes+2)<<3);

    return nLen;
}


/******************************************************************************
// Name:            ijSkipMarker
// Description:     Skip current marker;
// Input Arguments:
//         pStream: Identifies IJBITTREAMSTATE data structure.
// Output Arguments:
//            NONE.
//                          
// Returns:          
//        [Success] IJX_RTCODE_OK
//        [Failure] IJX_RTCODE_BAGARG
//                  IJX_RTCODE_F_INSUFFICIENTBUF
//                  IJX_RTCODE_E_ERRPARAM.
//
******************************************************************************/
IJXRESULT ijSkipMarker(IJBITTREAMSTATE *pStream)
{

    IJXRESULT rtCode=_ReadMarkerLength(pStream);
    if( !IJX_SUCCEEDED(rtCode) ){
        return rtCode;
    }

    IJSEEKSTREAM(rtCode, pStream);

    return IJX_RTCODE_OK;
}

/******************************************************************************
// Name:            ijReadMarker
// Description:     Read a marker from stream;
// Input Arguments:
//         pStream: Identifies IJBITTREAMSTATE data structure.
// Output Arguments:
//         pMarker: Identifies marker.
//                          
// Returns:          
//        [Success] IJX_RTCODE_OK
//        [Failure] IJX_RTCODE_BAGARG
//                  IJX_RTCODE_F_INSUFFICIENTBUF
//                  IJX_RTCODE_E_ERRPARSE
//                  IJX_RTCODE_E_ERRPARAM.
//                  
******************************************************************************/
IJXRESULT ijReadMarker(int *pMarker,
                       IJBITTREAMSTATE *pStream)
{
    int   i, nMaxBufLen, nUsedBytes;
    Ipp8u *pBitStreamBuf;

    if (IJX_MARKER_NONE!=pStream->nMarker) {
        *pMarker=pStream->nMarker;
        pStream->nMarker = IJX_MARKER_NONE;
        return IJX_RTCODE_OK;
    }

    *pMarker      = -1;
    nUsedBytes    = ((pStream->nUsedBufBitsLen+7)>>3);
    pBitStreamBuf = &(pStream->pBitStream)[nUsedBytes];
    nMaxBufLen    = pStream->nMaxBufLen;

//	printf("marker 0: nUsedBytes = %d, nMaxBufLen = %d\n", nUsedBytes, nMaxBufLen);

    if (!ISSTREAMBUFENOUGH(2, nUsedBytes, nMaxBufLen)) {
        return IJX_RTCODE_W_INSUFFICIENTBUF;
    }


    if (0xff!=*pBitStreamBuf) {
        return IJX_RTCODE_E_ERRPARSE;
    }
    
    for (i=nUsedBytes; i<nMaxBufLen; i++) {
        nUsedBytes++;
        pBitStreamBuf++;
        if (0xff!=*pBitStreamBuf) {
            *pMarker=*pBitStreamBuf;
            nUsedBytes++;
            break;
        }
    }

    if (-1==*pMarker) {
        return IJX_RTCODE_W_INSUFFICIENTBUF;
    }

    pStream->nUsedBufBitsLen=(nUsedBytes<<3);

    return IJX_RTCODE_OK;
}

/******************************************************************************
// Name:            ijRead_COM
// Description:     Read string from stream;
// Input Arguments:
//        pSrcData: Identifies string data buffer.
//           pnLen: Indicates string data buffer length.
//         pStream: Identifies IJBITTREAMSTATE data structure.
// Output Arguments:
//           pnLen: Indicates valid string length in pSrcData buffer.
//                          
// Returns:          
//        [Success] IJX_RTCODE_OK
//        [Failure] IJX_RTCODE_BAGARG
//                  IJX_RTCODE_F_INSUFFICIENTBUF
//                  IJX_RTCODE_E_ERRPARAM.
//                  
******************************************************************************/
IJXRESULT ijRead_COM(char *pSrcData, 
                     int  *pnLen, 
                     IJBITTREAMSTATE *pStream)
{
    /*
    // Length of COM block	(2 bytes)
    // COM Data             (Variable length) 
    */
    int nLen, nValidLen;
    IJXRESULT rtCode;

    rtCode=_ReadMarkerLength(pStream);
    if( !IJX_SUCCEEDED(rtCode) ){
        return rtCode;
    }
    nLen=rtCode;
    if (0==nLen) {
        return IJX_RTCODE_OK;
    }

    if (0>=*pnLen) {
        IJSEEKSTREAM(nLen, pStream);
        return IJX_RTCODE_OK;
    }

    nValidLen=*pnLen=_IJX_MIN(*pnLen, nLen);

    ijReadStreamBytes(pSrcData, nValidLen, pStream);  
    
    if (nValidLen<nLen){
        nLen-=nValidLen;
        IJSEEKSTREAM(nLen, pStream);
    }

    return IJX_RTCODE_OK;
} 

/******************************************************************************
// Name:            ijRead_APP0Class
// Description:     Read class of APP0;
// Input Arguments:
//         pStream: Identifies IJBITTREAMSTATE data structure.
// Output Arguments:
//         pnClass: Indicates the class of APP0.
//                  0: JFIF; 1: JFXX; 2:IJXM
//           pnLen: Indicates the length of APP0.
//                          
// Returns:          
//        [Success] IJX_RTCODE_OK
//        [Failure] IJX_RTCODE_BAGARG
//                  IJX_RTCODE_F_INSUFFICIENTBUF
//                  IJX_RTCODE_E_ERRPARAM.
//                  IJX_RTCODE_F_NOTSUPPORTEDIDENT
//                  
******************************************************************************/
IJXRESULT ijRead_APP0Class(int *pnClass, 
                           int *pnLen,
                           IJBITTREAMSTATE *pStream)
{

    /*
    // Length of APP0 block	(2 bytes)
    // Block ID			    (5 bytes - ASCII "JFIF\0")
    //                      (5 bytes - ASCII "JFXX\0")
    //                      (5 bytes - ASCII "IJXM\0")
    //----------------------------------------------------
    //
    */

    int    nLen;
    int    nUsedBytes;
    Ipp8u  *ptr;
    IJXRESULT rtCode;

    rtCode=_ReadMarkerLength(pStream);
    if( !IJX_SUCCEEDED(rtCode) ){
        return rtCode;
    }
    nLen=rtCode;

    if (5>=nLen) {
        return IJX_RTCODE_W_NOTSUPPORTEDIDENT;
    }

    nUsedBytes=((pStream->nUsedBufBitsLen+7)>>3);
    ptr=&pStream->pBitStream[nUsedBytes];
    
    /*
    // JFIF
    */
    if (ptr[0] == 'J' &&
        ptr[1] == 'F' &&
        ptr[2] == 'I' &&
        ptr[3] == 'F' &&
        ptr[4] == 0x00  ){
        *pnClass=0;
        *pnLen=nLen-5;
        IJSEEKSTREAM(5, pStream);
        return IJX_RTCODE_OK;
    }

    /*
    // JFXX
    */
    if (ptr[0] == 'J' &&
        ptr[1] == 'F' &&
        ptr[2] == 'X' &&
        ptr[3] == 'X' &&
        ptr[4] == 0x00  ){
        *pnClass=1;
        *pnLen=nLen-5;
        IJSEEKSTREAM(5, pStream);
        return IJX_RTCODE_OK;
    }

    /*
    // IJXM
    */
    if (ptr[0] == 'I' &&
        ptr[1] == 'J' &&
        ptr[2] == 'X' &&
        ptr[3] == 'M' &&
        ptr[4] == 0x00  ){
        *pnClass=2;
        *pnLen=nLen-5;
        IJSEEKSTREAM(5, pStream);
        return IJX_RTCODE_OK;
    }

    *pnClass=-1;
    *pnLen=nLen;
    IJSEEKSTREAM(nLen, pStream);
    return IJX_RTCODE_W_NOTSUPPORTEDIDENT;
} 

/******************************************************************************
// Name:            ijRead_APP0_JFIF
// Description:     Read JFIF of APP0;
// Input Arguments:
//       pnJFIFLen: Identifies length of APP0_JFIF.
//         pStream: Identifies IJBITTREAMSTATE data structure.
// Output Arguments:
//       pnJFIFLen: Identifies current length of APP0_JFIF.
//       pApp0JFIF: Identifies IJAPP0_JFIF structure.        
//                          
// Returns:          
//        [Success] IJX_RTCODE_OK
//        [Failure] IJX_RTCODE_BAGARG
//                  IJX_RTCODE_F_INSUFFICIENTBUF
//                  IJX_RTCODE_E_ERRPARAM.
//                  
******************************************************************************/
IJXRESULT ijRead_APP0_JFIF(int *pnJFIFLen,
                           IJAPP0_JFIF *pApp0JFIF,
                           IJBITTREAMSTATE *pStream)
{

    /*
    // Length of APP0 block	(2 bytes)
    // Block ID			    (5 bytes - ASCII "JFIF\0")
    //----------------------------------------------------
    // Version Major, Minor	(2 bytes - 0x01, 0x01)
    // Units			    (1 byte - 0x00 = none, 0x01 = inch, 0x02 = cm)
    // Xdpu			        (2 bytes - dots per unit horizontal)
    // Ydpu			        (2 bytes - dots per unit vertical)
    // Thumbnail X size		(1 byte)
    // Thumbnail Y size		(1 byte)
    */
    int nUsedBytes;
    Ipp8u *ptr;

    if (9>*pnJFIFLen) {
        return IJX_RTCODE_E_ERRPARAM;
    }

    nUsedBytes=((pStream->nUsedBufBitsLen)>>3);
    ptr=&pStream->pBitStream[nUsedBytes];

    pApp0JFIF->nVersion = (ptr[0]<<16)|(ptr[1]&0xff);
    ptr+=2;
    pApp0JFIF->Units    = ptr[0];
    ptr++;
    pApp0JFIF->Xdpu     = MAKE_INT16(ptr);
    ptr+=2;
    pApp0JFIF->Ydpu     = MAKE_INT16(ptr);
    ptr+=2;
    pApp0JFIF->nThumbWidth  = ptr[0];
    pApp0JFIF->nThumbHeight = ptr[1];

    *pnJFIFLen-=9;
    IJSEEKSTREAM(9, pStream);

    return IJX_RTCODE_OK;
}
 
/******************************************************************************
// Name:            ijRead_APP0_JFXX
// Description:     Read JFXX of APP0;
// Input Arguments:
//       pnJFIFLen: Identifies length of APP0_JFIF.
//         pStream: Identifies IJBITTREAMSTATE data structure.
// Output Arguments:
//       pnJFIFLen: Identifies current length of APP0_JFIF.
//       pApp0JFIF: Identifies IJAPP0_JFXX structure.        
//                          
// Returns:          
//        [Success] IJX_RTCODE_OK
//        [Failure] IJX_RTCODE_BAGARG
//                  IJX_RTCODE_F_INSUFFICIENTBUF
//                  IJX_RTCODE_E_ERRPARAM
//                  IJX_RTCODE_E_NOTSUPPORTEDIDENT
//
******************************************************************************/
IJXRESULT ijRead_APP0_JFXX(int *pnJFIFLen,
                           IJAPP0_JFXX *pApp0JFXX,
                           IJBITTREAMSTATE *pStream)
{
    /*
    // Length of APP0 block	(2 bytes)
    // Block ID			    (5 bytes - ASCII "JFXX\0")
    //----------------------------------------------------
    // Extension Code		(1 byte) 
    //                        0x10 = Thumbnail in JPEG;
    //                        0x11 = Thumbnail in 1byte/pixel; 
    //                        0x13 = Thumbnail in 3bytes/pixel)
    // Thumbnail Data       (Variable length) 
    */
    int nUsedBytes;
    Ipp8u *ptr;

    if (1>*pnJFIFLen) {
        return IJX_RTCODE_E_ERRPARAM;
    }

    nUsedBytes=((pStream->nUsedBufBitsLen)>>3);
    ptr=&pStream->pBitStream[nUsedBytes];

    pApp0JFXX->nMode=ptr[0];
    pnJFIFLen--;

    switch(pApp0JFXX->nMode) {
        case 0x10:
            IJSEEKSTREAM(*pnJFIFLen, pStream);
            //IJSEEKSTREAM(1, pStream);
            break;
        case 0x11:
        case 0x13:
            pApp0JFXX->nThumbWidth=ptr[1];
            pApp0JFXX->nThumbHeight=ptr[2];
            IJSEEKSTREAM(*pnJFIFLen, pStream);
            //IJSEEKSTREAM(3, pStream);
            break;
        default:
            IJSEEKSTREAM(*pnJFIFLen, pStream);
            return IJX_RTCODE_E_NOTSUPPORTEDIDENT;
    }

    
    return IJX_RTCODE_OK;
}

/******************************************************************************
// Name:            ijRead_APP0_IJXM
// Description:     Read JFXX of APP0;
// Input Arguments:
//       pnJFIFLen: Identifies length of APP0_JFIF.
//         pStream: Identifies IJBITTREAMSTATE data structure.
// Output Arguments:
//       pnJFIFLen: Identifies current length of APP0_JFIF.
//       pApp0JFIF: Identifies IJAPP0_JFXX structure.        
//                          
// Returns:          
//        [Success] IJX_RTCODE_OK
//        [Failure] IJX_RTCODE_BAGARG
//                  IJX_RTCODE_F_INSUFFICIENTBUF
//                  IJX_RTCODE_E_ERRPARAM
//                  IJX_RTCODE_E_NOTSUPPORTEDIDENT
//
******************************************************************************/
IJXRESULT ijRead_APP0_IJXM(  int   nMarkerByteLength,
                             Ipp32u *pnJPEGCodeMode,
                             IIPIMAGESPEC *pImageSpec,
                             IWPWAVESPEC  *pWaveSpec,
                             IJMOTIONSPEC *pMotionSpec,
                             IJBITTREAMSTATE    *pStream)
{    
    /*
    // Length of APP0 block	(2 bytes)
    // IJXM Indentifier     (5 Bytes: "IJXM\0")
    //-----------------------------------------------7Bytes----------
    // nMode;               (4bytes: Still|Motion)
    // nNumComponents;      (1bytes)
    // nMFrameWidth;        (2bytes)
    // nMFrameHeight;       (2bytes)
    // nMRate               (2Bytes)
    // nMFrameRSTInterval;  (2bytes)
    // nMFrameCount;        (4bytes)
    //-----------------------------------------------17Bytes---------
    // nWaveMode            (4Bytes) 
    // nWaveChannels;       (1byte)
    // nWaveSamplesPerSec;  (4Bytes)
    // nAvgBytesPerSec;     (4Bytes)
    // nWaveBlockAlign;     (4Bytes)
    // nWaveBitsPerSample;  (2Bytes)
    //-----------------------------------------------19Bytes---------
    */

    int nUsedBytes;
    Ipp8u *ptr;

    if (1>nMarkerByteLength) {
        return IJX_RTCODE_E_ERRPARAM;
    }

    nUsedBytes=((pStream->nUsedBufBitsLen)>>3);
    ptr=&pStream->pBitStream[nUsedBytes];

    /*------------------ Video --------------------*/

    /* nJPEGCodeMode (Still|Motion) */
    *pnJPEGCodeMode=MAKE_INT32(ptr);
    pMotionSpec->nCodeMode=(*pnJPEGCodeMode)&IJX_MODE_MOTION_MASK;
    ptr+=4;
    /* nNumComponents */
    pImageSpec->nNumComponent=*ptr++;
    /* nMFrameWidth */
    pImageSpec->nWidth=MAKE_INT16(ptr);
    ptr+=2;
    /* nMFrameHeight */
    pImageSpec->nHeight=MAKE_INT16(ptr);
    ptr+=2;
    /* nMRate */
    pMotionSpec->nRate=MAKE_INT16(ptr);
    ptr+=2;
    /* nMFrameRSTInterval */
    pMotionSpec->nFrameRSTInterval=MAKE_INT16(ptr);
    ptr+=2;                 
    /* nMFrameCount */
    pMotionSpec->nFrameCount=MAKE_INT32(ptr);
    ptr+=4;

    /*------------------ Wave --------------------*/

    /* nWaveMode */
    pWaveSpec->nCodeMode=MAKE_INT32(ptr);
    ptr+=4;

    /* nWaveChannels */
    pWaveSpec->nChannels=*ptr++;
    
    /* nWaveSamplesPerSec */
    pWaveSpec->nSamplesPerSec=MAKE_INT32(ptr);
    ptr+=4;
    /* nAvgBytesPerSec */
    pWaveSpec->nAvgBytesPerSec=MAKE_INT32(ptr);
    ptr+=4;
    /* nWaveBlockAlign */
    pWaveSpec->nBlockAlign=MAKE_INT32(ptr);
    ptr+=4;
    /* nWaveBitsPerSample */
    pWaveSpec->nBitsPerSample=MAKE_INT16(ptr);
    ptr+=2;

    IJSEEKSTREAM(nMarkerByteLength, pStream);

    return IJX_RTCODE_OK;
}


/******************************************************************************
// Name:            ijRead_APP14
// Description:     Read APP14 (Skip).
// Input Arguments:
//         pStream: Identifies IJBITTREAMSTATE data structure.
// Output Arguments:
//            NONE.
//                          
// Returns:          
//        [Success] IJX_RTCODE_OK
//        [Failure] IJX_RTCODE_BAGARG
//                  IJX_RTCODE_F_INSUFFICIENTBUF
//                  IJX_RTCODE_E_ERROR
//                  
******************************************************************************/
IJXRESULT ijRead_APP14(IJBITTREAMSTATE *pStream)
{
    return ijSkipMarker(pStream);
}


/******************************************************************************
// Name:            ijRead_DQT
// Description:     Read dequantization tables
// Input Arguments:
// pDCTDequantTables: 
//                  Identifies DCT-dequantization tables.
//     nMaxQTables: Indicates maximum number of tables identidied by pDCTDequantTables.
//         pStream: Identifies IJBITTREAMSTATE data structure.
// Output Arguments:
// pDCTDequantTables: 
//                  Identifies DCT-dequantization tables with new values.
//                          
// Returns:          
//        [Success] IJX_RTCODE_OK
//        [Failure] IJX_RTCODE_BAGARG
//                  IJX_RTCODE_F_INSUFFICIENTBUF
//                  IJX_RTCODE_E_ERRPARAM
//                  IJX_RTCODE_F_NOTSUPPORTEDPRECISION
//                  
******************************************************************************/
IJXRESULT ijRead_DQT(Ipp32s *pDCTDequantTables,
                     int    nMaxQTables,
                     IJBITTREAMSTATE *pStream )
{
    /*
    // Length of DQT block      (2 bytes)
    // Table precision          (0.5 byte)
    // Table identifier         (0.5 byte)
    // Table values             (n bytes)
    */
    int ident, precision;
    int i,  nLen, nDQTLen;
    int nUsedBytes;
    Ipp8u   *ptr;
    Ipp8u   qTable[64*sizeof(Ipp16u)+31];
    Ipp16u  *pQTable;
    Ipp32s  *pDCTQTable;
    IJXRESULT rtCode;
    const Ipp8u pZagZigIndex[64] =
    {
        0,  1,  8, 16,  9,  2,  3, 10,
        17, 24, 32, 25, 18, 11,  4,  5,
        12, 19, 26, 33, 40, 48, 41, 34,
        27, 20, 13,  6,  7, 14, 21, 28,
        35, 42, 49, 56, 57, 50, 43, 36,
        29, 22, 15, 23, 30, 37, 44, 51,
        58, 59, 52, 45, 38, 31, 39, 46,
        53, 60, 61, 54, 47, 55, 62, 63
    };

    rtCode=_ReadMarkerLength(pStream);
    if( !IJX_SUCCEEDED(rtCode) ){
        return rtCode;
    }
    nLen=nDQTLen=rtCode;

    nUsedBytes=((pStream->nUsedBufBitsLen)>>3);
    ptr=&pStream->pBitStream[nUsedBytes];
    pQTable=(Ipp16u *)IIP_ALIGN_32B(qTable);

    do{
        if (nLen<65) {
            return IJX_RTCODE_E_ERRPARAM;
        }

        ident=ptr[0]&0x0f;
        precision=(0==((ptr[0]>>4)&0x0f))?8:16;
        if (0>ident||ident>=nMaxQTables){
            return IJX_RTCODE_E_ERRPARAM;
        }

        if (8!=precision) {
            //ijSeek_Marker(nLen, pStream);
            return IJX_RTCODE_E_NOTSUPPORTEDPRECISION;
        }

        pDCTQTable=&pDCTDequantTables[ident*64];
        ptr++;

        for (i=0; i<64; i++){
            pQTable[pZagZigIndex[i]]=ptr[i];
        }

        ippiDCTQuantInvTableInit_JPEG_16u32s(pQTable, pDCTQTable);

        ptr+=64;
        nLen-=65;

    }while (0<nLen);

    IJSEEKSTREAM(nDQTLen, pStream);

    return IJX_RTCODE_OK;
}

/******************************************************************************
// Name:            ijRead_DHT
// Description:     Read Huffman decoding tables.
// Input Arguments:
//    pDCHuffTable: Identifies a array of IppJPEGDeHuffTable strcuture for DC values.
//    pACHuffTable: Identifies a array of IppJPEGDeHuffTable strcuture for AC values.
//     nMaxQTables: Indicates maximum number of tables identidied by pDCTDequantTables.
//         pStream: Identifies IJBITTREAMSTATE data structure.
// Output Arguments:
//    pDCHuffTable: Identifies updated array of IppJPEGDeHuffTable strcuture for DC values.
//    pACHuffTable: Identifies updated of IppJPEGDeHuffTable strcuture for AC values.
//                          
// Returns:          
//        [Success] IJX_RTCODE_OK
//        [Failure] IJX_RTCODE_BAGARG
//                  IJX_RTCODE_F_INSUFFICIENTBUF
//                  IJX_RTCODE_E_ERRPARAM
//                  
******************************************************************************/
IJXRESULT ijRead_DHT( IppJPEGDeHuffTable *pDCHuffTable,
                        IppJPEGDeHuffTable *pACHuffTable,
                        int    nMaxTables,
                        IJBITTREAMSTATE *pStream)
{
    int    i, ident, type;
    int    nLen, nValLen, nDHTLen;
    int    nUsedBytes;
    Ipp8u  *ptr;
    Ipp8u  *pHuffbits;
    Ipp8u  *pHuffvals;
    IppJPEGDeHuffTable *pHuffTable;
    IJXRESULT rtCode;

    rtCode=_ReadMarkerLength(pStream);
    if( !IJX_SUCCEEDED(rtCode) ){
        return rtCode;
    }
    nDHTLen=nLen=rtCode;

    nUsedBytes=((pStream->nUsedBufBitsLen)>>3);
    ptr=&pStream->pBitStream[nUsedBytes];


    do{
        if (17>nLen) {
            return IJX_RTCODE_E_ERRPARAM;
        }

        ident=(ptr[0]&0x0f);
        type=((ptr[0]&0xf0)>>4);
        if (0>ident || ident>nMaxTables){
            return IJX_RTCODE_E_ERRPARAM;
        }

        switch(type) {
            case 0:
                pHuffTable=pDCHuffTable;
                break;
            case 1:
                pHuffTable=pACHuffTable;
                break;
            default:
                return IJX_RTCODE_E_ERRPARAM;
        }

        pHuffTable=&pHuffTable[ident];
        pHuffbits=++ptr;

        nLen-=17;

        nValLen = 0;
        for (i = 0; i < 16; i++){
            nValLen += pHuffbits[i];
        }

        if (0>nValLen||nValLen>nLen){
            return IJX_RTCODE_E_ERRPARAM;
        }

        ptr+=16;
        pHuffvals=ptr;
        ptr+=nValLen;
        nLen-=nValLen;

        ippiDecodeHuffmanTableInit_JPEG_8u(pHuffbits, 
                                        pHuffvals,
                                        pHuffTable);
    }while (0<nLen);

    IJSEEKSTREAM(nDHTLen, pStream);

    return IJX_RTCODE_OK;
}
 

/******************************************************************************
// Name:            ijRead_DNL
// Description:     Read number of lines.
// Input Arguments:
//         pStream: Identifies IJBITTREAMSTATE data structure.
// Output Arguments:
//       pNumLines: Identifies number of lines.
//                          
// Returns:          
//        [Success] IJX_RTCODE_OK
//        [Failure] IJX_RTCODE_BAGARG
//                  IJX_RTCODE_F_INSUFFICIENTBUF
//                  IJX_RTCODE_E_ERRPARAM
//                  
******************************************************************************/
IJXRESULT ijRead_DNL(int *pNumLines,
                     IJBITTREAMSTATE *pStream)
{
    int    nLen;
    int    nUsedBytes;
    Ipp8u  *ptr;
    IJXRESULT rtCode;

    rtCode=_ReadMarkerLength(pStream);
    if( !IJX_SUCCEEDED(rtCode) ){
        return rtCode;
    }
    nLen=rtCode;
    if (2>nLen){
        return IJX_RTCODE_E_ERRPARAM;
    }

    nUsedBytes=((pStream->nUsedBufBitsLen)>>3);
    ptr=&pStream->pBitStream[nUsedBytes];

    *pNumLines=ptr[0]<<8|ptr[1];

    IJSEEKSTREAM(nLen, pStream);
    
    return rtCode; 
}

/******************************************************************************
// Name:            ijRead_DRI
// Description:     Read restart interval.
// Input Arguments:
//         pStream: Identifies IJBITTREAMSTATE data structure.
// Output Arguments:
//    pRstInterval: Identifies restart invertal value read from stream.
//                          
// Returns:          
//        [Success] IJX_RTCODE_OK
//        [Failure] IJX_RTCODE_BAGARG
//                  IJX_RTCODE_F_INSUFFICIENTBUF
//                  IJX_RTCODE_E_ERRPARAM
//                  
******************************************************************************/
IJXRESULT ijRead_DRI(int *pRstInterval, 
                       IJBITTREAMSTATE *pStream)
{
    int    nLen;
    int    nUsedBytes;
    Ipp8u  *ptr;
    IJXRESULT rtCode;

    rtCode=_ReadMarkerLength(pStream);
    if( !IJX_SUCCEEDED(rtCode) ){
        return rtCode;
    }
    nLen=rtCode;
    if (2>nLen){
        return IJX_RTCODE_E_ERRPARAM;
    }

    nUsedBytes=((pStream->nUsedBufBitsLen)>>3);
    ptr=&pStream->pBitStream[nUsedBytes];

    *pRstInterval=ptr[0]<<8|ptr[1];

    IJSEEKSTREAM(nLen, pStream);
    
    return IJX_RTCODE_OK; 
}

/******************************************************************************
// Name:            ijRead_SOF
// Description:     Read Start Of Frame.
// Input Arguments:
//         pStream: Identifies IJBITTREAMSTATE data structure.
//Output Arguments:
//      pFrameInfo: Identifies IJFRAMEINFO strcuture.
//           pComp: Identifies IJCOMPSPEC strcuture.
//                          
// Returns:          
//        [Success] IJX_RTCODE_OK
//        [Failure] IJX_RTCODE_BAGARG
//                  IJX_RTCODE_F_INSUFFICIENTBUF
//                  IJX_RTCODE_E_ERRPARAM
//                  
******************************************************************************/
IJXRESULT ijRead_SOF( IJFRAMESPEC *pFrameSpec,
                      IJCOMPSPEC  *pComp,
                      IJBITTREAMSTATE *pStream )
{
    /*
    // Length of SOF block      (2 bytes)
    // Sample precision         (1 byte)
    // Height                   (2 bytes)
    // Width                    (2 bytes)
    // Number of components     (1 byte)
    // Component Info
    //   Component identifier   (1 byte)
    //   H sampling factor      (0.5 byte)
    //   V sampling factor      (0.5 byte)
    //   Q-Table identifier     (1 byte)
    */

    int    i, nIndex;
    int    nLen, nValidLen, nNumComps;
    int    nUsedBytes;
    Ipp8u  *ptr;
    IJXRESULT rtCode;

    rtCode=_ReadMarkerLength(pStream);
    if( !IJX_SUCCEEDED(rtCode) ){
        return rtCode;
    }
    nLen=rtCode;

    if (6>=nLen){
       return IJX_RTCODE_E_ERRPARAM;
    }

    nUsedBytes=((pStream->nUsedBufBitsLen)>>3);
    ptr=&pStream->pBitStream[nUsedBytes];

    pFrameSpec->nPrecision=ptr[0];
    pFrameSpec->nHeight=ptr[1]<<8|ptr[2];
    pFrameSpec->nWidth=ptr[3]<<8|ptr[4];
    pFrameSpec->nNumComps=nNumComps=ptr[5];
    ptr+=6;

    if (0>=nNumComps || MAX_COMPONETS<nNumComps){
       return IJX_RTCODE_E_ERRPARAM;
    }

    nValidLen=3*nNumComps;
    if ((nLen-6)<nValidLen){
       return IJX_RTCODE_E_ERRPARAM;
    }

    for (i=0; i<nNumComps; i++){
        nIndex=*ptr-1;
        pComp[nIndex].nIdentifier=*ptr-1;
        ptr++;
        pComp[nIndex].nHSampling=(ptr[0]>>4);
        pComp[nIndex].nVSampling=(ptr[0]&0x0f);
        ptr++;
        pComp[nIndex].nQuantTableIndex=*ptr;
        ptr++;
    }

    IJSEEKSTREAM(nLen, pStream);

    return IJX_RTCODE_OK;
} 

/******************************************************************************
// Name:            ijRead_SOF
// Description:     Read Start Of Frame.
// Input Arguments:
//         pStream: Identifies IJBITTREAMSTATE data structure.
// Output Arguments:
//      pFrameInfo: Identifies IJFRAMEINFO strcuture.
//           pComp: Identifies IJCOMPSPEC strcuture.
//                          
// Returns:          
//        [Success] IJX_RTCODE_OK
//        [Failure] IJX_RTCODE_BAGARG
//                  IJX_RTCODE_F_INSUFFICIENTBUF
//                  IJX_RTCODE_E_ERRPARAM
//                  
******************************************************************************/
IJXRESULT ijRead_SOS(IJSCANSPEC *pScanSpec,
                     IJCOMPSPEC *pComp,
                     IJBITTREAMSTATE *pStream)
{
    /*
    // Length of SOS block      (2 bytes)
    // number of Comp in scan   (1 byte)
    // Component Info
    //   Component identifier   (1 byte)
    //   DC-Huff identifier     (0.5 byte)
    //   AC-Huff identifier     (0.5 byte)
    //   Q-Table identifier     (1 byte)
    // Start of spectral        (1 byte)
    // End of spectral          (1 byte)
    // SA-High                  (0.5 byte)
    // SE-Low                   (0.5 byte)
    */
    int    i, nIndex;
    int    nLen, nValidLen, nNumComps;
    int    nUsedBytes;
    Ipp8u  *ptr;
    IJXRESULT rtCode;

    rtCode=_ReadMarkerLength(pStream);
    if( !IJX_SUCCEEDED(rtCode) ){
        return rtCode;
    }
    nLen=rtCode;

    if (1>=nLen){
       return IJX_RTCODE_E_ERRPARAM;
    }

    nUsedBytes=((pStream->nUsedBufBitsLen)>>3);
    ptr=&pStream->pBitStream[nUsedBytes];
    pScanSpec->nNumComps=nNumComps=ptr[0];
    if (0>=nNumComps||MAX_COMPONETS<nNumComps) {
       return IJX_RTCODE_E_ERRPARAM;
    }

    nValidLen=nNumComps*2;
    
    if ((nValidLen+4)>nLen){
       return IJX_RTCODE_E_ERRPARAM;
    }

    ptr++;

    for (i=0; i<nNumComps; i++){
        nIndex=*ptr-1;
        ptr++;
        pComp[nIndex].nDCHuffTableIndex=(ptr[0]>>4);
        pComp[nIndex].nACHuffTableIndex=(ptr[0]&0x0f);
        ptr++;
        pScanSpec->ppCompSpec[i]=&(pComp[nIndex]);
    }

    pScanSpec->ss=*ptr++;
    pScanSpec->se=*ptr++;
    pScanSpec->ah=ptr[0]>>4;
    pScanSpec->al=ptr[0]&0x0f;

    IJSEEKSTREAM(nLen, pStream);

    return IJX_RTCODE_OK;
}

/******************************************************************************
// Name:            ijGetWaveStream
// Description:     
// Input Arguments:
// Output Arguments:
// Returns:          
//                     
//                  
******************************************************************************/
IJXRESULT ijGetWaveStream(void **ppWaveStreamBuf,
                          int  *pnByteLength,
                          IJBITTREAMSTATE *pStream)
{
    unsigned int nUsedBytes;
    IJXRESULT rtCode;

    rtCode=_ReadMarkerLength(pStream);
    if( !IJX_SUCCEEDED(rtCode) ){
        return rtCode;
    }
    *pnByteLength=rtCode;

    nUsedBytes=((pStream->nUsedBufBitsLen)>>3);
    *ppWaveStreamBuf=&pStream->pBitStream[nUsedBytes];
    
    IJSEEKSTREAM(rtCode, pStream);

    //pStream->nUsedBufBitsLen=(nUsedBytes+rtCode)<<3;

    return IJX_RTCODE_OK;
}

/******************************************************************************
// Name:            ijxGetTimeStamp
// Description:     
// Input Arguments:
// Output Arguments:
// Returns:          
//                     
//                  
******************************************************************************/
IJXRESULT ijGetTimeStamp(IJTIMESPEC     *pTimeSpec, 
                         IJBITTREAMSTATE *pStream)
{
    int   i, nUsedBytes;   

    Ipp8u *ptr;
    IJXRESULT rtCode;

    rtCode=_ReadMarkerLength(pStream);
    if( !IJX_SUCCEEDED(rtCode)){
        return rtCode;
    }

    nUsedBytes=((pStream->nUsedBufBitsLen)>>3);
    ptr=&pStream->pBitStream[nUsedBytes];

    switch (rtCode) {
        case 4:
            pTimeSpec->nFlags       = IJX_TIME_COUNTER;
            pTimeSpec->nTimeCounter = MAKE_INT32(ptr);
            break;
        case 6:
            pTimeSpec->nFlags       = IJX_TIME_DATE;
            for (i=0; i<6; i++) {
                pTimeSpec->nDate[i] = *ptr++;
            }
            break;
        case 10:
            pTimeSpec->nFlags       = IJX_TIME_COUNTER|IJX_TIME_DATE;
            pTimeSpec->nTimeCounter = MAKE_INT32(ptr);
            ptr+=4;
            for (i=0; i<6; i++) {
                pTimeSpec->nDate[i] = *ptr++;
            }
            break;
        default:
            break;
    }

    
    IJSEEKSTREAM(rtCode, pStream);
    //pStream->nUsedBufBitsLen=(nUsedBytes+rtCode)<<3;

    return IJX_RTCODE_OK;
}

/* EOF */
